#pragma once

#include <iostream>
#include <unistd.h>
#include <queue>
#include <pthread.h>

#define NUM 5

using namespace std;

template<class T>
class threadPool
{
private:
    queue<T> _task_queue;
    int _thread_num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
private:
    bool IsEmpty()
    {
        return _task_queue.size()==0;
    }
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void Wait()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }
public:
    threadPool(int num=NUM)
        :_thread_num(num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }
    ~threadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
    static void* Routine(void*arg)
    {
        pthread_detach(pthread_self());
        threadPool* self=(threadPool*)arg;

        while(true)
        {
            self->LockQueue();
            while(self->IsEmpty())
            {
                self->Wait();
            }
            T task;
            self->Pop(task);
            self->UnLockQueue();

            task.Run();
        }
    }

    void ThreadPoolInit()
    {
        pthread_t tid;
        for(int i=0;i<_thread_num;++i)
        {
            pthread_create(&tid,nullptr,Routine,this);
        }
    }
    void Push(const T& task)
	{
	    LockQueue();
	    _task_queue.push(task);
	    UnLockQueue();
	    WakeUp();
	}
    void Pop(T& task)
	{
	    task = _task_queue.front();
	    _task_queue.pop();
	}
	
};
